package main

import "fmt"
import "bufio"
import "os"
import "code.google.com/p/ehedgehog/expr-parsing/lex"
import "strconv"

type Any interface {}
  
type Context struct {
  env map[string]Any
  }
  
func (this Context) LookUp( spelling string ) Any {
  return this.env[spelling]
  }
  
func (this Context) Bind( spelling string, value Any ) Context {
  copy := make(map[string]Any)
  for key, value := range this.env { copy[key] = value }
  copy[spelling] = value
  return Context{copy}
  }
  
func NewContext() Context {
  return Context{ make(map[string]Any) }
  }
  
type Expr interface {
  String() string
  Operands() []Expr
  Run( Context ) Any
  }

type ID struct {
  spelling string
  }

func (this ID) Operands() []Expr {
  return nil
  }

func (this ID) String() string {
  return this.spelling
  }
  
func (this ID) Run( c Context ) Any {
  return c.LookUp( this.spelling )
  }

func Id( s string ) Expr {
  return ID{s}
  }

type NUM struct {
  spelling string
  }
  
func (this NUM) Run( c Context ) Any {
  result, _ := strconv.Atoi( this.spelling )
  return result
  }

func Num( s string ) Expr {
  return NUM{s}
  }

func (this NUM) String() string {
  return this.spelling
  }

func (this NUM) Operands() []Expr {
  return nil
  }

type BAR struct {
  e Expr
  a Expr
  }

func (this BAR) Run( c Context ) Any {
  fmt.Printf( ">> NOT DONE YET\n" )
  return nil
  }
  
func (this BAR) Operands() []Expr {
  return []Expr{this.e, this.a}
  }

func (this BAR) String() string {
  return "(" + this.e.String() + " | " + this.a.String() + ")"
  }

type APP struct {
  x Expr
  f Expr
  }

func App( x, f Expr ) Expr {
  return APP{x, f}
  }

func (this APP) Run( c Context ) Any {
  f := this.f.Run( c )
  x := this.x.Run( c )
  if F, ok := f.(func ( x Any ) Any); ok { return F(x) }
  return nil
  }
  
func (this APP) String() string {
  return this.x.String() + "." + this.f.String()
  }

func (this APP) Operands() []Expr {
  return []Expr{this.x, this.f}
  }

type LAM struct {
  v ID
  b Expr
  }
  
func (this LAM) Run( c Context ) Any {
  return func ( x Any ) Any {
    c2 := c.Bind( this.v.spelling, x )
    return this.b.Run( c2 )
    }
  }

func (this LAM) String() string {
  return "(" + this.v.String() + " => " + this.b.String() + ")"
  }

func (this LAM) Operands() []Expr {
  return []Expr{this.v, this.b}
  }

func Lam( v, b Expr ) Expr {
  if x, ok := v.(ID); ok { return LAM{x, b} }
  return nil
  }

func Bar( e, a Expr ) Expr {
  return BAR{e, a}
  }

func expect( l *lex.Lexer, e lex.Type ) {
  t, _ := l.Next()
  if t != e { fmt.Printf( "! expected %v, got %v\n", e, t ) }
  }

func parseOperand( l *lex.Lexer ) Expr {
  switch t, s := l.Next(); t {
    case lex.ID:
      return Id(s)

    case lex.NUM:
      return Num(s)

    case lex.LPAR:
      e := Parse( l )
      t, _ := l.Next()
      switch t {
        case lex.RPAR:
          return e

        case lex.BAR:
          a := Parse( l )
          expect( l, lex.RPAR )
          return Bar( e, a )

        case lex.ARROW:
          a := Parse( l )
          expect( l, lex.RPAR )
          return Lam( e, a )
        }
      fmt.Printf( "! that didn't end well\n" )
      return e
    }
  return Id("not really")
  }

func Parse( l *lex.Lexer ) Expr {
  x := parseOperand( l )
  t, s := l.Next()
  if t == lex.DOT {
    f := parseOperand( l )
    x = App( x, f )
    } else {
      l.PutBack( t, s )
    }
  return x
  }

func main() {
  fmt.Printf( ">> regard here the crystals of wisdom.\n" )
  r := bufio.NewReader( os.Stdin )
  l := lex.Lex( r )
  for {
      e := Parse( l )
      fmt.Printf( ">> %v\n", e )
      result := e.Run( NewContext() )
      fmt.Printf( ">> %v\n", result );
//     t, spelling := l.Next()
//     if (t == lex.EOF) { break }
//     fmt.Printf( "| %v: %v\n", t, spelling )
    }  
  }

